/*
 * Project: BoboDesignPattern
 * 
 * File Created at 2017年6月25日
 * 
 * Copyright 2012 Greenline.com Corporation Limited.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * Greenline Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Greenline.com.
 */
package test.thread.wait_notify.transformers_synchronized;

/**
 * @Type EnergySystem
 * @Desc
 * @author boboge
 * @date 2017年6月25日
 * @Version V1.0
 */
public class EnergySystem {

    private final double[] energyBoxes;

    private final Object lockObject = new Object();

    /**
     * 初始化能量盒子
     * 
     * @param n
     * @param initialEngry
     */
    public EnergySystem(int n, double initialEngry) {
        energyBoxes = new double[n];
        for (int i = 0; i < energyBoxes.length; i++) {
            energyBoxes[i] = initialEngry;
        }
    }

    /**
     * 转移能量
     * 
     * @param from
     * @param to
     * @param amount
     */
    public void transfer(int from, int to, double amount) {

        synchronized (lockObject) {
            // if (energyBoxes[from] < amount) {
            // return;
            // }
            // 条件不满足的时候都会被阻挡，而不是继续竞争cpu资源
            while (energyBoxes[from] < amount) {
                try {
                    lockObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

            System.out.println(Thread.currentThread().getName());
            energyBoxes[from] -= amount;
            System.out.printf("从%d转移%10.2f单位能量到%d", from, amount, to);
            energyBoxes[to] += amount;
            System.out.printf("能量总和：%10.2f%n", getTotalEnergies());
            // 通知所有等待线程集合（wait set） 可以竞争锁
            lockObject.notifyAll();
        }
    }

    /**
     * 获取能量世界的能量总和
     * 
     * @return
     */
    private double getTotalEnergies() {
        double sum = 0;
        for (double amount : energyBoxes) {
            sum += amount;
        }
        return sum;
    }

    /**
     * 获得能量盒子长度
     * 
     * @return
     */
    public int getBoxAmount() {
        return energyBoxes.length;
    }

}
